package pl.umk.mat.fred.unicore.urc.storagemanagement.actions;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.PlatformUI;
import org.unigrids.services.atomic.types.GridFileType;

import de.fzj.unicore.wsrflite.xmlbeans.BaseFault;

import pl.umk.mat.fred.unicore.urc.storagemanagement.dialogs.FindDialog;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.BelowStorageNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.CatalogNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.GridNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.MultiplyCatalogNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.Node;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.StorageNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.unicore.Storage;
import pl.umk.mat.fred.unicore.urc.storagemanagement.views.StorageBrowserView;

public class FindAction extends Action {

	public class SearchResult extends SearchPair {

		/*
		 * used to select first from catalogs which are merged in MultiCatalog
		 */
		private boolean primary = false;
		
		public SearchResult(Storage storage, String path) {
	    super(storage, path);
    }

		public boolean isPrimary() {
    	return primary;
    }

		public void setPrimary(boolean primary) {
    	this.primary = primary;
    }
	}
	
	private class SearchTarget extends SearchPair {

		public SearchTarget(Storage storage, String path) {
	    super(storage, path);
    }
	}
	
	private abstract class SearchPair {
		
		private Storage storage;
		private String path;
		
		public SearchPair(Storage storage, String path) {
			this.storage = storage;
			this.path = path;
		}
		
		public Storage getStorage() {
    	return storage;
    }
		public void setStorage(Storage storage) {
    	this.storage = storage;
    }
		public String getPath() {
    	return path;
    }
		public void setPath(String path) {
    	this.path = path;
    }
		
	}
	
	StorageBrowserView view;
	
	public FindAction(StorageBrowserView view) {
		this.view = view;
		this.setText("Find");
	}
	
	public void run() {
		final FindDialog dialog = new FindDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell());
		ISelection selection = view.getTreeViewer().getSelection();
		final Node selectedNode = (Node)((IStructuredSelection) selection).getFirstElement();
		int result = dialog.open();
		if (result == 0) {
			Job job = new Job("Find " + dialog.getCriteria()) {
				@Override
				protected IStatus run(IProgressMonitor monitor) {
					System.out.println("Run find");
					monitor.beginTask("", IProgressMonitor.UNKNOWN);
					List<FindAction.SearchTarget> searchTargets = new ArrayList<FindAction.SearchTarget>();
					
					if (selectedNode instanceof GridNode) {
						GridNode gn = (GridNode) selectedNode;
						for (Node n : gn.getChildren()) {
							StorageNode sn = (StorageNode) n;
							searchTargets.add(new SearchTarget(sn.getStorage(), "/"));
						}
					} else if (selectedNode instanceof StorageNode) {
						StorageNode sn = (StorageNode) selectedNode;
						searchTargets.add(new SearchTarget(sn.getStorage(), "/"));
					} else if (selectedNode instanceof BelowStorageNode) {
						if (selectedNode instanceof MultiplyCatalogNode) {
							MultiplyCatalogNode mn = (MultiplyCatalogNode) selectedNode;
							for (CatalogNode cn : mn.getCatalogs()) {
								searchTargets.add(new SearchTarget(cn.getStorage(), cn.getPath()));
							}
						} else {
							BelowStorageNode bn = (BelowStorageNode) selectedNode;
							searchTargets.add(new SearchTarget(bn.getStorage(), bn.getPath()));
						}
					}
					
					if (!searchTargets.isEmpty()) {
						final List<SearchResult> finded = new ArrayList<SearchResult>();
						for (SearchTarget st : searchTargets) { 
							try {
		            GridFileType[] result = st.getStorage().find(st.getPath(), true, dialog.getCriteria(), 
		            		dialog.getUseRegexec(), null, null);
		            for (GridFileType gft : result) {
		            	String name = gft.getPath().substring(gft.getPath().lastIndexOf("/"));
		            	boolean add = false;
		            	if (dialog.getUseRegexec()) {
		            		Pattern pattern = Pattern.compile(dialog.getCriteria());
		            		Matcher matcher = pattern.matcher(name);
		            		add = matcher.find();
		            	} else {
		            		add = name.indexOf(dialog.getCriteria()) != -1;
		            	}
		            	if (add) {
		            		finded.add(new SearchResult(st.getStorage(), gft.getPath()));
		            	}
		            }
	            } catch (BaseFault e) {
	            } catch (Exception e) {
	            }
						}
						
						PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
							@Override
							public void run() {
								if (finded.isEmpty()) {
		            	new MessageDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(),
		            			"", null, "There are no matching files.", MessageDialog.INFORMATION,
		            			new String[]{"OK"}, 0).open();
		            } else {
		            	System.out.println("Fred add");
		            	view.addNaviBarActions();
		            	ListIterator<SearchResult> itr = finded.listIterator();
		            	view.setSearchResultIterator(itr);
		            	if (finded.size() > 1) {
		            		view.getPrevSearchResultAction().enable();
		            		view.getNextSearchResultAction().enable();
		            		view.getNextSearchResultAction().clearListOfMulticatalogs();
		            	} else {
		            		view.getPrevSearchResultAction().disable();
		            		view.getNextSearchResultAction().disable();
		            	}
		            	view.getNextSearchResultAction().run();
		            }
							}
						});
					}
					return Status.OK_STATUS;
				}
			};
			job.schedule();
		}
	}
	
}
